package com.ofsoft.weixin.mp.api;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.ofsoft.weixin.core.WeixinException;
import com.ofsoft.weixin.core.utils.JsonUtil;
import com.ofsoft.weixin.core.utils.StringUtil;
import com.ofsoft.weixin.mp.AppConfig;
import com.ofsoft.weixin.mp.api.cache.DefaultAccessTokenCache;
import com.ofsoft.weixin.mp.api.cache.IAccessTokenCache;

/**
 * accessToken处理
 * 
 * @author OF
 * @date 2017年10月16日
 */
public class AccessTokenConfig {
	private static Logger log = LoggerFactory
			.getLogger(AccessTokenConfig.class);
	/** 减去秒数 */
	private static int OutTime = 10;

	/**
	 * 获取accessToken
	 * 
	 * @return
	 */
	public static String getAccessToken() {
		try {
			Map<String, Object> token = null;
			String json = accessTokenCache.getStr(AppConfig.getAppId());
			if (StringUtil.isNotBlank(json)) {
				token = JSONObject.parseObject(json);
				// 判断是否过期
				if (isAvailable(token)) {
					return (String) token.get("access_token");
				}
			}
			token = refreshAccessToken();
			if (token != null) {
				return (String) token.get("access_token");
			}
			return null;
		} catch (NullPointerException e) {
			e.printStackTrace();
			throw new WeixinException("获取AccessToken 失败 请检查AppID 是否设置");
		}
	}

	public static Map<String, Object> setAccessToken() {
		ApiResponse result = AccessTokenApi.getAccessTokenApi();
		if (result.isSuccessful()) {
			Integer expiresIn = Integer.valueOf(result.get("expires_in")
					.toString());
			Long expiredTime = 0L;
			if (expiresIn != null)
				// 过期时间加两小时 减10秒是为了网络误差 *1000 变成毫秒
				expiredTime = (System.currentTimeMillis() + ((expiresIn - OutTime) * 1000));
			// 用户缓存时还原
			if (result.getResult().containsKey("expiredTime")) {
				expiredTime = (Long) result.getResult().get("expiredTime");
			}
			result.set("expiredTime", expiredTime);
			accessTokenCache.set(AppConfig.getAppId(),
					JsonUtil.objectToJson(result.getResult()));
			return result.getResult();
		} else {
			log.error("获取accessToken 失败  code [{}] msg [{}]",
					result.getErrorCode(), result.getErrorMsg());
		}
		return null;

	}

	/**
	 * 失败连续三次重复
	 */
	public static Map<String, Object> refreshAccessToken() {
		Map<String, Object> result = null;
		for (int i = 1; i <= 3; i++) {
			log.debug("获取 access token 第 [" + i + "] 次");
			result = setAccessToken();
			if (result != null) {
				return result;
			}
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return result;

	}

	private static IAccessTokenCache accessTokenCache = new DefaultAccessTokenCache();

	public static void setAccessTokenCache(IAccessTokenCache accessTokenCache) {
		AccessTokenConfig.accessTokenCache = accessTokenCache;
	}

	public static IAccessTokenCache getAccessTokenCache() {
		return AccessTokenConfig.accessTokenCache;
	}

	public static boolean isAvailable(Map<String, Object> token) {
		Long expiredTime = (Long) token.get("expiredTime");
		if (expiredTime == null || expiredTime == 0)
			return false;
		if (token.get("errcode") != null)
			return false;
		if (expiredTime < System.currentTimeMillis())
			return false;
		return token.get("access_token") != null;
	}
}
